﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../impl/head.h"
#include "callback_impl.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 

namespace xos_box
{

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static callback_impl::POOL * pool_ptr = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    callback_impl::callback_impl()
    {
        m_bQuit = false;
        m_pThread = 0;
        m_pEvent = 0;
        m_pList = 0;
    }

    callback_impl::~callback_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int callback_impl::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    int callback_impl::init()
    {
        int nRet = 0;

        if( 0 == nRet )
        {
            nRet = mgr::get()->create( enumObj::BOX_OBJ_LIST, ( void ** )&m_pList );
        }

        if( 0 == nRet )
        {
            nRet = mgr::xos()->create( xos::i_xos::XOS_OBJ_EVENT, ( void ** )&m_pEvent );
        }

        if( 0 == nRet )
        {
            nRet = mgr::xos()->create( xos::i_xos::XOS_OBJ_THREAD, ( void ** )&m_pThread );
            if( 0 == nRet )
            {
                nRet = m_pThread->create( thread, this );
            }
        }

        return nRet;
    }

    int callback_impl::term()
    {
        int nRet = 0;

        if( m_pThread && m_pEvent )
        {
            m_bQuit = true;
            m_pEvent->set_event();
            m_pThread->wait();
            m_pThread->release();
            m_pThread = 0;
        }

        if( m_pList )
        {
            m_pList->release();
            m_pList = 0;
        }

        if( m_pEvent )
        {
            m_pEvent->release();
            m_pEvent = 0;
        }

        m_bQuit = false;

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    void * callback_impl::thread( void * lpData )
    {
        callback_impl & obj = *( callback_impl * )lpData;

        while( !obj.m_bQuit )
        {
            obj.m_pEvent->wait( xos::i_event::EVENT_WAIT_INFINITE );
            obj.run();
        }

        return 0;
    }

    int callback_impl::run()
    {
        int nRet = 0;

        bool bFinished = false;

        while( !bFinished )
        {
            xos::f_runnable f_run = 0;
            i_msg * p = 0;

			m_pList->lock();
            if( ( p = ( i_msg * )m_pList->front( 0 ) ) )
            {
                m_pList->pop_front();
            }
			m_pList->un_lock();

            if( p )
            {
                f_run = p->get_runnable( 0, 0 );
            }
            else
            {
                bFinished = true;
            }

            if( f_run )
            {
                f_run( p );
            }
        }

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

	int callback_impl::prior_notify( i_msg *& p )
	{
		int nRet = 0;

		m_pList->lock();
		m_pList->push_front( p );
		m_pList->un_lock();
		m_pEvent->set_event();
        p = 0;

		return nRet;
	}

    int callback_impl::notify( i_msg *& p )
    {
        int nRet = 0;

		m_pList->lock();
        m_pList->push_back( p );
		m_pList->un_lock();
        m_pEvent->set_event();
        p = 0;

        return nRet;
    }

    int callback_impl::size()
    {
        int ret = 0;

        m_pList->lock();
        ret = m_pList->size();
        m_pList->un_lock();

        return ret;
    }

} // xos
